#include "script.h"

#include <stdio.h>


class CTest
{
public:
	virtual void test()
	{
		printf("Base call\n");
	}

	virtual ~CTest()
	{
		printf("Destroying class\n");
	}

	static int construct(HSQUIRRELVM vm)
	{
		CTest* t = new CTest();
		StackHandler sh( vm );
		HSQOBJECT obj = sh.GetObjectHandle(1);
		t->sqTest = SquirrelFunction<void>(obj, "test");

		return PostConstruct<CTest>(vm, t, release);
	}

	SQ_DECLARE_RELEASE(CTest)

	void callTest()
	{
		if (!sqTest.func.IsNull())
			sqTest();
		else
			test();
	}

	SquirrelFunction<void> sqTest;
};


class CTest2
	:public CTest
{
public:
	virtual void test()
	{
		printf("Derived call\n");
	}

	static int construct(HSQUIRRELVM vm)
	{
		CTest* t = new CTest2();
		StackHandler sh( vm );
		HSQOBJECT obj = sh.GetObjectHandle(1);
		t->sqTest = SquirrelFunction<void>(obj, "test");

		return PostConstruct<CTest>(vm, t, release);
	}

	SQ_DECLARE_RELEASE(CTest)
};

class CTestManager
{
private:
	typedef struct 
	{
		CTest *test;
		SquirrelFunction<void> sqTest;
	}TRec;
	CTest* m_test[10];
	int m_count;

	CTestManager()
	{
		m_count = 0;
		printf("Created testManager\n");
	}

	static CTestManager *_this;
public:
	static CTestManager *getInstance()
	{
		if (!_this)
			_this = new CTestManager();
		return _this;
	}

	void addTest(CTest *t)
	{
		printf("Adding test\n");
		m_test[m_count++] = t;
	}

	SQInteger sq_addTest(CTest* test, HSQUIRRELVM vm)
	{
		SQInteger nargs = sq_gettop(vm); //number of arguments

		StackHandler sh(vm);
		SquirrelObject obj =  sh.GetObjectHandle(2);

		SquirrelFunction<void> sqFunc(obj, "test");
		sqFunc();

		return 0;
	}
	void update()
	{
		printf("Updating %d tests...\n",m_count);
		for (int i=0;i<m_count;i++)
//			m_test[i]->test();
			m_test[i]->callTest();
	};
};

CTestManager *CTestManager::_this = NULL;

DECLARE_INSTANCE_TYPE(CTest);
DECLARE_INSTANCE_TYPE(CTest2);
DECLARE_INSTANCE_TYPE(CTestManager);

bool runScript(char *path)
{
	FILE *f = fopen(path, "rb");
	if (!f)
		return FALSE;

	fseek(f, 0, SEEK_END);
	long len = ftell(f);
	fseek(f,0,SEEK_SET);

	char *tmp = new char[len+1];
	fread(tmp, len, 1, f);
	fclose(f);

	tmp[len] = 0;

	SquirrelObject obj = SquirrelVM::CompileBuffer(tmp);
	SquirrelVM::RunScript(obj);

	delete[] tmp;

	return TRUE;
}

int main(int argc,char * argv[]) 
{
	SquirrelVM::Init();

	SQClassDef<CTest>("CTest")
		.staticFunc(&CTest::construct, "constructor")
		.func(&CTest::test, "test");

	SQClassDef<CTest2>("CTest2", "CTest")
		.staticFunc(&CTest2::construct, "constructor");


	SQClassDefNoConstructor<CTestManager>("CTestManager")
		.staticFunc(&CTestManager::getInstance, "getInstance")
		.func(&CTestManager::addTest, "addTest")
		.func(&CTestManager::sq_addTest, "sqTest")
		.func(&CTestManager::update, "update");

	runScript("../src/test.nut");

	SquirrelVM::Shutdown();
}